package com.heatup.apt.common.util.Netty;

import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;

import java.net.InetSocketAddress;

/**
 * Created by blank on 2017/11/20 上午10:15
 */
public class BootstrapServer {

    /**
     * 1. 创建要给新的 ServerBootstrap 来创建新的 SocketChannel 管道并绑定他们
     * 2. 指定 EventLoopGroup 用于从注册的 ServerChannel 中获取EventLoop 和接收到的管道
     * 3. 指定要使用的管道类
     * 4. 设置子处理器用于处理接收的管道的 I/O 和数据
     * 5. 通过配置引导来绑定管道
     */
    public static void ServerBootstrap(){

        NioEventLoopGroup group = new NioEventLoopGroup();
        ServerBootstrap bootstrap = new ServerBootstrap(); //1
        bootstrap.group(group) //2
                .channel(NioServerSocketChannel.class) //3
                .childHandler(new SimpleChannelInboundHandler<ByteBuf>() { //4
                    @Override
                    protected void channelRead0(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf) throws Exception {
                        System.out.println("Received data");
                        byteBuf.clear();
                    }
                });


        ChannelFuture future = bootstrap.bind(new InetSocketAddress(8080)); //5
        future.addListener(new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture channelFuture) throws Exception {
                if (channelFuture.isSuccess()) {
                    System.out.println("Server bound");
                } else {
                    System.err.println("Bound attempt failed");
                    channelFuture.cause().printStackTrace();
                }
            }
        });

    }


    /**
     * 1. 创建一个新的 ServerBootstrap 来创建新的 SocketChannel 管道并且绑定他们
     * 2. 指定 EventLoopGroups 从 ServerChannel 和接收到的管道来注册并获取 EventLoops
     * 3. 指定 Channel 类来使用
     * 4. 设置处理器用于处理接收到的管道的 I/O 和数据
     * 5. 创建一个新的 Bootstrap 来连接到远程主机
     * 6. 设置管道类
     * 7. 设置处理器来处理 I/O
     * 8. 使用相同的 EventLoop 作为分配到接收的管道
     * 9. 连接到远端
     * 10. 连接完成处理业务逻辑 (比如, proxy)
     * 11. 通过配置了的 Bootstrap 来绑定到管道
     */
    public static void EventLoopSharedBetweenChannelsWithServerBootstramAndBootstrap(){

        final ServerBootstrap bootstrap = new ServerBootstrap(); //1
        bootstrap.group(new NioEventLoopGroup(), //2
                new NioEventLoopGroup()).channel(NioServerSocketChannel.class) //3
                .childHandler( //4
                        new SimpleChannelInboundHandler<ByteBuf>() {
                            ChannelFuture connectFuture;


                            @Override
                            public void channelActive(ChannelHandlerContext ctx) throws Exception {
                                Bootstrap bootstrap1 = new Bootstrap(); //5
                                bootstrap1.channel(NioSocketChannel.class) //6
                                        .handler(new SimpleChannelInboundHandler<ByteBuf>() { //7
                                            @Override
                                            protected void channelRead0(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
                                                System.out.println("Received data");
                                            }
                                        });
                                bootstrap1.group(ctx.channel().eventLoop()); //8
                                connectFuture = bootstrap1.connect(new InetSocketAddress("apt.heatup.cn", 80)); //9
                            }

                            @Override
                            protected void channelRead0(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf) throws Exception {
                                if (connectFuture.isDone()) {
                                    // do something with the data //10
                                }
                            }
                        }

                );

        ChannelFuture future = bootstrap.bind(new InetSocketAddress(8080)); //11
        future.addListener(new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture channelFuture) throws Exception {
                if (channelFuture.isSuccess()) {
                    System.out.println("Server bound");
                } else {
                    System.err.println("Bound attempt failed");
                    channelFuture.cause().printStackTrace();
                }
            }
        });

    }

}
